package com.kr.weitao.util.mongodb;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.*;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Data
@Log4j2
public class MongodbClient {
  private MongodbProperties mongodbProperties;

  private static MongoClient mongoClient = null;

  private static MongoTemplate mongoTemplate = null;

  private static MongoDbFactory mongoDbFactory = null;

  public MongodbClient() {}

  public MongoClient getMongoClient() {
    if (mongoClient == null) {
      ArrayList seedList = new ArrayList();
      String[] hosts = mongodbProperties.getHost().split(",");

      for (int credentials = 0; credentials < hosts.length; ++credentials) {
        seedList.add(new ServerAddress(hosts[credentials], mongodbProperties.getPort()));
      }

      ArrayList var5 = new ArrayList();
      var5.add(
          MongoCredential.createScramSha1Credential(
              mongodbProperties.getUsername(),
              mongodbProperties.getDefaultDataBase(),
              mongodbProperties.getPassword().toCharArray()));
      MongoClientOptions options =
          MongoClientOptions.builder()
              .requiredReplicaSetName(mongodbProperties.getReplSetName())
              .socketTimeout(20000)
              .maxWaitTime(25000)
              .threadsAllowedToBlockForConnectionMultiplier(5)
              .connectTimeout(2000)
              .heartbeatConnectTimeout(1000)
              .socketKeepAlive(true) // 是否保持长链接
              .connectionsPerHost(100) // 最大连接数
              .minConnectionsPerHost(20) // 最小连接数
              .build();
      mongoClient = new MongoClient(seedList, var5, options);
    }

    return mongoClient;
  }

  public MongoTemplate getMongoTemplate() {
    if (mongoTemplate == null) {
      try {
        if (mongoClient == null) {
          mongoClient = this.getMongoClient();
        }
        if (mongoDbFactory == null) {
          mongoDbFactory = new SimpleMongoDbFactory(mongoClient, mongodbProperties.getDatabase());
        }
        if (mongoTemplate == null) {
          MappingMongoConverter e =
              new MappingMongoConverter(mongoDbFactory, new MongoMappingContext());
          e.setTypeMapper(new DefaultMongoTypeMapper((String) null));
          mongoTemplate = new MongoTemplate(mongoDbFactory, e);
        }
      } catch (Exception var2) {
        log.error(var2.getMessage());
      }
    }
    return mongoTemplate;
  }

  private DBCollection getCollection(String collectionName) {
    try {
      return this.getMongoTemplate().getCollection(collectionName);
    } catch (Exception e) {
      log.error(e.getMessage());
      return null;
    }
  }

  public boolean insert(String collectionName, Map info) {
    WriteResult wr =
        this.getCollection(collectionName).insert(new DBObject[] {new BasicDBObject(info)});
    return wr.getN() > 0;
  }

  public boolean delete(String collectionName, Map info) {
    BasicDBObject delObj = new BasicDBObject();
    delObj.putAll(info);
    WriteResult wr = this.getCollection(collectionName).remove(delObj);
    return wr.getN() > 0;
  }

  public boolean update(String collectionName, Map newMap, Map oldMap) {
    BasicDBObject newObj = new BasicDBObject();
    BasicDBObject oldObj = new BasicDBObject();
    newObj.putAll(newMap);
    oldObj.putAll(oldMap);
    WriteResult wr = this.getCollection(collectionName).update(oldObj, newObj);
    return wr.getN() > 0;
  }

  public List query(String collectionName, Map keyMap) {
    BasicDBObject ref = new BasicDBObject();
    ref.putAll(keyMap);
    DBCursor dbCursor = this.getCollection(collectionName).find(ref);
    return DBCursorToList(dbCursor);
  }

  public JSONArray query(String collectionName, BasicDBObject keyMap) {
    DBCursor dbCursor = this.getCollection(collectionName).find(keyMap);
    return disposeDBCursor(dbCursor);
  }

  public JSONArray query(
      String collectionName,
      BasicDBObject keyMap,
      int page_num,
      int page_size,
      String sort_key,
      int sort_type) {
    DBCursor dbCursor = this.getCollection(collectionName).find(keyMap);
    dbCursor = sortAndPage(dbCursor, page_num, page_size, sort_key, sort_type);
    return disposeDBCursor(dbCursor);
  }

  public static DBCursor sortAndPage(
      DBCursor dbCursor, int page_num, int page_size, String sort_key, int sort_type) {
    if (page_num >= 0 && page_size > 0) {
      dbCursor = dbCursor.skip((page_num - 1) * page_size).limit(page_size);
    }
    if (!sort_key.equals("") && null != sort_key) {
      BasicDBObject sort_obj = new BasicDBObject(sort_key, Integer.valueOf(sort_type));
      dbCursor = dbCursor.sort(sort_obj);
    }
    return dbCursor;
  }

  private JSONArray disposeDBCursor(DBCursor dbCursor) {
    JSONArray array = new JSONArray();
    while (dbCursor.hasNext()) {
      DBObject obj = dbCursor.next();
      array.add(JSONObject.parseObject(obj.toString(), JSONObject.class));
    }
    return array;
  }

  private List DBCursorToList(DBCursor dbCursor) {
    ArrayList list = new ArrayList();
    while (dbCursor.hasNext()) {
      DBObject obj = dbCursor.next();
      list.add(obj.toMap());
    }
    return list;
  }
  /**
   * 日期范围查询
   *
   * @param date_field 查询的日期字段
   * @param start_time 开始时间 2016-11-24 11:07:45
   * @param end_time 结束时间
   * @return
   */
  public static BasicDBObject rangeQuery(String date_field, String start_time, String end_time) {
    BasicDBObject rangeQuery = new BasicDBObject();
    Map map = new HashedMap(); //获取日期范围
    map.put(QueryOperators.GTE, start_time);
    map.put(QueryOperators.LTE, end_time);
    rangeQuery.put(date_field, map);
    return rangeQuery;
  }
}
